Une introduction à journald

Par Jérémy Rosen  le 28 mars 2022

Introduction

Mal connu, souvent décrié mais maintenant inévitable, journald est l'un des composants de systemd où le manque de connaissance est le plus regrettable.

Journald est la nouvelle infrastructure de gestion des logs introduite par le projet systemd. Jounald centralise l'ensemble des logs d'un système et gère de façon transparente les différentes sources. 

Dans cet article nous allons vous présenter quelques exemples "main dans le cambouis" d'utilisation de journald qui vous permettront de facilement retrouver vos marques et commencer à découvrir toute la puissance de cet outil comparé à un système de log traditionnel.

Quelques exemples d'utilisation

Afin de comprendre l'intérêt de journald nous allons présenter quelques exemples.

Récupération des logs noyau

Journald sait lire les logs noyau depuis /dev/kmsg. La commande suivante permet donc d'afficher les mêmes traces que dmesg.

$ journalctl -k

 

févr. 11 15:16:38 logrus kernel: microcode: microcode updated early to revision 0xea, date = 2021-01-06

févr. 11 15:16:38 logrus kernel: Linux version 5.15.0-3-amd64 (debian-kernel@lists.debian.org) (gcc-11 (Debian 11.2.0-14) 11.2.0, GNU ld (GNU Binutils >

févr. 11 15:16:38 logrus kernel: Command line: BOOT_IMAGE=/vmlinuz-5.15.0-3-amd64 root=/dev/mapper/logrus--vg-root ro quiet intel_idle.max_cstate=4 sys>

févr. 11 15:16:38 logrus kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'

févr. 11 15:16:38 logrus kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'

févr. 11 15:16:38 logrus kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'

févr. 11 15:16:38 logrus kernel: x86/fpu: Supporting XSAVE feature 0x008: 'MPX bounds registers'

févr. 11 15:16:38 logrus kernel: x86/fpu: Supporting XSAVE feature 0x010: 'MPX CSR'

févr. 11 15:16:38 logrus kernel: x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256

févr. 11 15:16:38 logrus kernel: x86/fpu: xstate_offset[3]:  832, xstate_sizes[3]:   64

févr. 11 15:16:38 logrus kernel: x86/fpu: xstate_offset[4]:  896, xstate_sizes[4]:   64

févr. 11 15:16:38 logrus kernel: x86/fpu: Enabled xstate features 0x1f, context size is 960 bytes, using 'compacted' format.

févr. 11 15:16:38 logrus kernel: signal: max sigframe size: 2032

févr. 11 15:16:38 logrus kernel: BIOS-provided physical RAM map:

févr. 11 15:16:38 logrus kernel: BIOS-e820: [mem 0x0000000000000000-0x0000000000057fff] usable

 

[...]

Le format n'est pas exactement identique à celui de dmesg, mais les logs sont là. En passant par journald, nous avons quelques bénéfices supplémentaires :

Pour récupérer uniquement les erreurs du noyau, nous avons donc la commande suivante :

$ journalctl -k -p 3

 

févr. 11 15:16:41 logrus kernel: i915 0000:00:02.0: [drm] *ERROR* DPLL 1 not locked

févr. 14 09:27:21 logrus kernel: Bluetooth: hci0: Reading supported features failed (-16)

févr. 14 17:24:53 logrus kernel: i915 0000:00:02.0: [drm] *ERROR* DPLL 1 not locked

févr. 15 08:04:02 logrus kernel: r8152 2-1.3:1.0: firmware: failed to load rtl_nic/rtl8153a-4.fw (-2)

févr. 15 08:04:02 logrus kernel: firmware_class: See https://wiki.debian.org/Firmware for information about missing firmware

févr. 15 08:04:02 logrus kernel: Bluetooth: hci0: Reading supported features failed (-16)

févr. 15 08:04:03 logrus kernel: hid-generic 0003:0D8C:0134.000D: No inputs registered, leaving

févr. 15 08:04:15 logrus kernel: hid-generic 0003:0D8C:0134.0012: No inputs registered, leaving

févr. 16 06:37:12 logrus kernel: i915 0000:00:02.0: [drm] *ERROR* failed to enable link training

févr. 16 06:37:12 logrus kernel: Bluetooth: hci0: Reading supported features failed (-16)

févr. 16 09:29:26 logrus kernel: Bluetooth: hci0: Reading supported features failed (-16)

févr. 16 18:08:19 logrus kernel: Bluetooth: hci0: Reading supported features failed (-16)

févr. 17 08:03:03 logrus kernel: r8152 2-1.3:1.0: firmware: failed to load rtl_nic/rtl8153a-4.fw (-2)

févr. 17 08:03:04 logrus kernel: Bluetooth: hci0: Reading supported features failed (-16)

févr. 17 08:03:05 logrus kernel: hid-generic 0003:0D8C:0134.001A: No inputs registered, leaving

 

[..]

 

Suivre les logs de plusieurs services

Il est assez courant de vouloir suivre les logs au fur et à mesure de leur génération. Lorsqu'on débogue des interactions entre plusieurs daemons, on souhaite également ne voir que les traces des unités systemd qui nous intéressent.

$ journalctl -u bluetooth.service -u systemd-udevd.service -f

 

févr. 11 15:16:38 logrus systemd[1]: Starting Rule-based Manager for Device Events and Files...

févr. 11 15:16:39 logrus systemd[1]: Started Rule-based Manager for Device Events and Files.

févr. 11 15:16:39 logrus mtp-probe[459]: checking bus 1, device 5: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-10"

févr. 11 15:16:39 logrus mtp-probe[460]: checking bus 1, device 3: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-5"

févr. 11 15:16:39 logrus mtp-probe[460]: bus: 1, device: 3 was not an MTP device

févr. 11 15:16:39 logrus mtp-probe[462]: checking bus 1, device 2: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3"

févr. 11 15:16:39 logrus mtp-probe[462]: bus: 1, device: 2 was not an MTP device

févr. 11 15:16:39 logrus mtp-probe[459]: bus: 1, device: 5 was not an MTP device

févr. 11 15:16:39 logrus systemd-udevd[415]: Using default interface naming scheme 'v250'.

févr. 11 15:16:40 logrus systemd-udevd[413]: Using default interface naming scheme 'v250'.

févr. 11 15:16:41 logrus systemd[1]: Starting Bluetooth service...

févr. 11 15:16:41 logrus bluetoothd[736]: Bluetooth daemon 5.62

févr. 11 15:16:41 logrus systemd[1]: Started Bluetooth service.

févr. 11 15:16:41 logrus bluetoothd[736]: Starting SDP server

févr. 11 15:16:41 logrus bluetoothd[736]: Bluetooth management interface 1.21 initialized

févr. 11 15:16:41 logrus bluetoothd[736]: profiles/sap/server.c:sap_server_register() Sap driver initialization failed.

févr. 11 15:16:41 logrus bluetoothd[736]: sap-server: Operation not permitted (1)

févr. 11 15:16:52 logrus systemd-udevd[1041]: vboxdrvu: /usr/lib/udev/rules.d/60-virtualbox-dkms.rules:2 Only network interfaces can be renamed, ignoring NAME="vboxdrvu".

févr. 11 15:16:52 logrus systemd-udevd[996]: vboxdrv: /usr/lib/udev/rules.d/60-virtualbox-dkms.rules:1 Only network in

Quelques notes sur cette commande :

Changer le format de sortie

Par défaut, les informations affichées par journalctl sont très similaires à celles que l'on obtient d'un fichier de log classique. Cependant, journald sauvegarde beaucoup plus d'informations que ça.

Générons un message et commençons par l'afficher avec tous les détails.

$ logger -p local0.3 -i --id=1 message de test

$ journalctl --facility=local0 -o verbose

 

 

Wed 2022-03-09 11:07:09.373580 CET [s=94e13f7bca824c1192e413d758f8882c;i=58e33;b=d56cd947e79841eba251133d2ed810d1;m=9a308c9d5e;t=5d9c642b3a15a;x=5779660f2e08be16]

    _TRANSPORT=syslog

    _UID=1000

    _GID=1000

    _BOOT_ID=d56cd947e79841eba251133d2ed810d1

    _MACHINE_ID=9e7936dad17a4aef95023a89630fc999

    _HOSTNAME=logrus

    PRIORITY=3

    SYSLOG_IDENTIFIER=jerros

    SYSLOG_PID=1

    _COMM=logger

    SYSLOG_FACILITY=16

    SYSLOG_TIMESTAMP=Mar  9 11:07:09

    MESSAGE=message de test

    _PID=232899

    _SOURCE_REALTIME_TIMESTAMP=1646820429373580

La commande logger nous permet d'écrire dans le syslog :

L'option -o verbose de journalctl nous permet d'afficher les détails.

L'ensemble des champs connus sont documentés dans man:systemd.journal-fields(7) mais c'est un format ouvert et les applications peuvent ajouter leurs propres champs.

Il existe de nombreux formats de sortie, permettant de choisir le format de la date (format ISO, temps UNIX, UTC...), de générer du JSON (en sélectionnant les champs lisibles ou sur une seule ligne, au format Server-Sent-Event ou Text-Sequence) par exemple.

Voir tous les nouveaux messages depuis "la dernière fois"

Quand on administre une machine, il est classique de vouloir voir les logs "à partir d'un certain point". Journalctl permet évidemment de filtrer par date ( -U, -S ) mais chaque message a un curseur unique qui permet de faire ça de façon plus fiable.

Nous pouvons faire ça à la main :

$ journalctl --show-cursor

 

[...]

mars 09 11:33:01 logrus py3status[2934]: Module `volume_status`: available sinks: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo', '9': 'regroup', '32': 'alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_>

mars 09 11:33:09 logrus py3status[2934]: Module `volume_status micro`: available sources: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo.monitor', '1': 'alsa_input.pci-0000_00_1f.3.analog-stereo', '19': 'regr>

mars 09 11:33:11 logrus py3status[2934]: Module `volume_status`: available sinks: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo', '9': 'regroup', '32': 'alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_>

-- cursor: s=94e13f7bca824c1192e413d758f8882c;i=58fce;b=d56cd947e79841eba251133d2ed810d1;m=9a8da1bcf6;t=5d9c69fc8c0f2;x=c2ed23ddb5d728bd

 

$ logger ceci est un test

$ journalctl --after-cursor 's=94e13f7bca824c1192e413d758f8882c;i=58fce;b=d56cd947e79841eba251133d2ed810d1;m=9a8da1bcf6;t=5d9c69fc8c0f2;x=c2ed23ddb5d728bd'

 

mars 09 11:33:53 logrus jerros[241325]: ceci est un test

 

L'option --show-cursor fait que journalctl affichera le curseur du dernier message après celui-ci. Nous pouvons ensuite utiliser l'option --after-cursor pour voir les nouveaux messages.

Nous pouvons également laisser journalctl enregistrer le curseur pour nous :

$ journalctl --cursor-file=./my_cursor

 

[...]

mars 09 11:38:21 logrus py3status[2934]: Module `volume_status`: available sinks: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo', '9': 'regroup', '32': 'alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_>

mars 09 11:38:29 logrus py3status[2934]: Module `volume_status micro`: available sources: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo.monitor', '1': 'alsa_input.pci-0000_00_1f.3.analog-stereo', '19': 'regr>

mars 09 11:38:31 logrus py3status[2934]: Module `volume_status`: available sinks: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo', '9': 'regroup', '32': 'alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_>

mars 09 11:38:39 logrus py3status[2934]: Module `volume_status micro`: available sources: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo.monitor', '1': 'alsa_input.pci-0000_00_1f.3.analog-stereo', '19': 'regr>

mars 09 11:38:41 logrus py3status[2934]: Module `volume_status`: available sinks: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo', '9': 'regroup', '32': 'alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_>

mars 09 11:38:49 logrus py3status[2934]: Module `volume_status micro`: available sources: {'0': 'alsa_output.pci-0000_00_1f.3.analog-stereo.monitor', '1': 'alsa_input.pci-0000_00_1f.3.analog-stereo', '19': 'regr>

 

$ cat my_cursor

s=94e13f7bca824c1192e413d758f8882c;i=5901d;b=d56cd947e79841eba251133d2ed810d1;m=9aa27ebd47;t=5d9c6b4a5c143;x=236b9957da4e62aa

$ logger ceci est un test

$ journalctl --cursor-file=./my_cursor

 

mars 09 11:40:01 logrus jerros[243272]: ceci est un test

Si le fichier n'existe pas, journalctl affichera tous les messages et créera le fichier curseur. Si le fichier existe, journalctl n'affichera que les messages générés après le curseur sauvegardé et mettra à jour le fichier.

Il est trivial de mettre ce genre de commandes dans un script shell pour récupérer régulièrement les nouveaux messages.

 

Rechercher des messages avec journalctl

Nous venons de voir les principes de base pour visionner des logs, mais il est au moins aussi important de pouvoir rechercher des logs qui nous intéressent.

Comment se limiter aux messages d'un boot donné.

Il est assez courant de ne s'intéresser qu'aux messages du boot actuel (ou du boot précédent, en cas de plantage)

Vous pouvez utiliser la commande "journalctl --list-boots" pour obtenir la liste de tous les boot de la machine, leur identifiant et la date du boot.

Comment retrouver les messages correspondant à une regex

Un grand classique, qui n'a jamais lancé une commande de type cat /var/log/mail | grep error

Pour chercher une option correspondante à une regex, journalctl fournit l'option --grep qui appliquera une regex au champ MESSAGE de nos logs et qui retournera les messages correspondants.

$ journalctl --grep test -o verbose

 

Wed 2022-03-09 11:40:01.968142 CET [s=94e13f7bca824c1192e413d758f8882c;i=5902a;b=d56cd947e79841eba251133d2ed810d1;m=9aa620046d;t=5d9c6b8470868;x=1abc6a59d873087c]

    _TRANSPORT=syslog

    SYSLOG_FACILITY=1

    _UID=1000

    _GID=1000

    _CAP_EFFECTIVE=0

    _BOOT_ID=d56cd947e79841eba251133d2ed810d1

    _MACHINE_ID=9e7936dad17a4aef95023a89630fc999

    _HOSTNAME=logrus

    PRIORITY=5

    SYSLOG_IDENTIFIER=jerros

    MESSAGE=ceci est un test

    _COMM=logger

    SYSLOG_TIMESTAMP=Mar  9 11:40:01

    _PID=243272

    _SOURCE_REALTIME_TIMESTAMP=1646822401968142

Notons que ce n'est pas un filtre sur la sortie de journalctl mais bien un filtre sur les messages. Nous avons toujours accès à l'ensemble des champs du message.

 

Recherche générique par clé/valeur.

Il est évident que derrière ces options, journalctl fait un filtrage sur les clés des messages. Il y a évidement une syntaxe générique pour faire des recherches directement sur une clé :

$ journalctl -N

 

_AUDIT_FIELD_CAPABILITY

NM_DEVICE

LIMIT

SLEEP

_TRANSPORT

USERSPACE_USEC

SYSLOG_RAW

_MACHINE_ID

AVAILABLE

_SOURCE_MONOTONIC_TIMESTAMP

NM_LOG_DOMAINS

_COMM

MESSAGE

SYSLOG_FACILITY

_UID

_SELINUX_CONTEXT

UNIT

INVOCATION_ID

MAX_USE_PRETTY

EXIT_STATUS

PRIORITY

CODE_FUNC

_AUDIT_FIELD_NAME

AVAILABLE_PRETTY

[...]

 

$ journalctl -F CODE_FUNC

 

udisks_state_check_mounted_fs_entry

handle_unmount

handle_mount

update_timeout

open_watchdog

cryptsetup_log_glue

session_finalize

session_stop_scope

bus_manager_log_shutdown

invoke_main_loop

unit_kill_common

update_complete

deactivate_net_auth_done_cb

impl_manager_activate_connection

manager_timeout

on_spawn_sigchld

[...]

 

 

$ journalctl CODE_FUNC=open_watchdog

déc. 10 16:43:10 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot cf260f9f1fba4eb8ab51da4068b72614 --

janv. 07 09:55:25 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot c0e74f4ac76c46aabd206e5fa4b2d889 --

janv. 19 16:48:06 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot 88047eac746b4f5cb4d391a7a3b1b1c2 --

févr. 26 07:42:30 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot c559220371274b9981c13527974f5b50 --

avril 14 09:08:44 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot c15e16c79f674475b20f1605d1a195fc --

mai 10 08:39:44 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot 9f8b1753da794b1daf5d0187a57a59aa --

juil. 12 09:13:25 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot 546c0c3bc2d14209816219373c0c6991 --

sept. 03 14:01:54 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot 15a8081591b545f993270bc737c53251 --

oct. 12 08:16:01 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot a32eb1c0dd3f42d49aac69e2c699c342 --

oct. 15 16:45:33 logrus systemd[1]: Using hardware watchdog 'iTCO_wdt', version 0, device /dev/watchdog

-- Boot caf11531d9e04b78bfff983e5f5afdc2 --

[...]

Grâce à cette syntaxe générique, et en explorant un peu, il est possible de n'afficher que les messages qui nous intéressent.

Intégration de journald dans vos services systemd

Journald ne fonctionne qu'avec systemd et ce dernier ne peut fonctionner sans journald. L'intégration de journald aux services systemd est donc plus que triviale, elle est automatique.

Par défaut, les stdout et stderr de vos services seront automatiquement connectés à journald et vous pourrez les voir dans vos logs (entremêlés avec les logs des autres services, en respectant l'ordre d'arrivé.

Il existe néanmoins un certain nombre de paramètres que vous pouvez mettre dans la section [Service] de vos services pour paramétrer le comportement de journald vis à vis des logs générés par ce service:

Enfin, si une ligne de stdout ou stderr commence par "<#>"  où # est une valeur entre 0 et 7, journald enlèvera ce préfixe et l'utilisera pour définir la priorité du message. Vous pouvez donc facilement gérer des messages de différentes priorités en ajoutant un préfixe dans vos affichages.

Configuration de journald

Gestion de la place disque

La hantise des administrateurs système (et l'une des cause de downtime les plus fréquentes) est le disque dur plein. Et lorsque le disque est plein, le coupable habituel est le système de log.

Journald surveille la place que les log consomment et est capable de supprimer automatiquement les anciens fichiers lorsque c'est nécessaire. Via les fichiers de configurations (man:journald.conf) vous pouvez contrôler:

Enfin, pour voir la place utilisée par les logs, utilisez la commande journalctl --disk-usage

Signature des logs

Journald est capable d'utiliser l'algorithme Forward Secure Signing pour signer périodiquement les logs. Lorsque cette sécurité est activée, journald signera régulièrement les logs (par défaut, toutes les 15 minutes) avec une clé à usage unique déduite de la signature précédente des logs. 

Une clé originale (conservée offline) permet de vérifier l'intégrité des logs. Cet algorithme fait partie des recommandations de l'ANSSI pour la gestion des logs système.

Journald et les conteneurs

Lire les logs d'un conteneur à posteriori

Par défaut, journald va lire les logs dans /var/log/journal/<machine-id>. Pour lire les logs d'un conteneur, il suffit donc de pointer journalctl vers un autre répertoire

Ces options permettent de bien simplifier les choses lorsque l'on doit jongler avec de nombreux conteneurs.

Intégrer les logs des différentes conteneurs dans les logs de l'hôte.

Systemd documente comment intégrer proprement un conteneur ici et c'est une lecture que je recommande à toute personne travaillant avec des conteneurs. En ce qui concerne journald, il est très simple de rendre les logs des invités visibles de façon transparente pour l'hôte.

Journald écrit ses logs dans le répertoire /var/log/journal/<machine-id> et journalctl lit depuis ce même répertoire. Comme chaque conteneur a un machine-id différent, il suffit d'utiliser des bind-mounts (ou des liens symboliques) pour que tous les répertoires /var/log/journal/<machine-id> de chaque conteneur apparaissent dans le répertoire /var/log/journal de l'hôte.

Une fois ces manipulations faites, il suffit d'invoquer journalctl avec l'option -m pour que les journaux de toutes les machines soient affichés, au lieu de se limiter au journal de l'hôte.

Journald et le réseau

Lorsque l'on travaille avec de nombreuses machines, on met généralement en place une infrastructure de log permettant d'envoyer vers un serveur centralisé les logs. Journald dispose d'outils permettant de mettre en place ce type d'infrastructure tout en conservant l'ensemble des informations supplémentaires que journald collectes.

La partie réseau de journald est souvent packagée séparément par les distributions. C'est notamment le cas sous Debian où vous trouverez ces outils dans le paquet systemd-journal-remote.

La logique push

Journald vient avec un utilitaire appelé systemd-journal-upload qui peut pousser les messages journald vers un serveur via une liaison HTTPS. L'utilisation du protocole HTTPS permet à la fois le chiffrement et l'authentification du serveur vers lequel les logs sont envoyés.

systemd-journal-upload peut être appelé périodiquement pour envoyer les nouveaux messages ou être lancé en mode follow auquel cas les messages seront envoyés au fur et à mesure de leur génération.

La logique pull

Selon l'organisation de notre architecture, il peut être souhaitable que les machines n'envoient pas leurs logs, mais qu'un serveur central les collecte régulièrement. Journald fournit un serveur HTTPS qui permet de récupérer les logs grâce à une API REST sur le port 19531.

Ici aussi, l'utilisation de HTTPS permet non seulement de chiffrer les flux mais également d'authentifier les connexions.

L'API REST est très complète. Elle permet notamment de filtrer les messages notifiés et de garder la connexion ouverte en attente de nouveaux messages.

Le serveur fournit également un outil de navigation web léger permettant d'explorer les logs d'une machine sans installer d'autres outils.

La collecte des logs

Nous sommes capable de pousser nos logs et nous sommes capable de fournir nos logs à quelqu'un qui vient les chercher. Il ne reste qu'à les collecter.

Journald fournit un programme appelé systemd-journal-remote qui sert à cela. Ce programme peut simultanément recevoir des connexions de systemd-journal-upload et aller chercher des logs sur systemd-journal-gateway. Les logs ainsi récupérés sont stockés dans /var/log/journal/remote (par défaut) et les logs peuvent également être périodiquement signés.

Pour afficher les logs ainsi récupérés, il faut utiliser l'option -m de journalctl.

l'API Journald

Dans le monde de l'embarqué, il est assez courant de devoir faire une application qui traite les logs, que ce soit pour les monitorer, les archiver ou détecter certains messages critiques.

Journald fournit une API permettant d'avoir facilement accès à toutes les possibilités que nous avons vu, mais à travers une API propre et sans jamais avoir à analyser du texte.

L'API permet, en particulier de choisir des filtres sur les messages et de recevoir un file-descriptor qui sera bloquant jusqu'à ce qu'un message correspondant à nos filtres soit reçu.

Voici un petit exemple en Python :

>>> import select

>>> from systemd import journal

>>> j = journal.Reader()

>>> j.seek_tail()

>>> journal.send('testing 1,2,3')   # make sure we have something to read

>>> j.add_match('MESSAGE=testing 1,2,3')

>>> p = select.poll()

>>> p.register(j, j.get_events())

>>> p.poll()                        

[(3, 1)]

>>> j.get_next()                    

{'_AUDIT_LOGINUID': 1000,

 '_CAP_EFFECTIVE': '0',

 '_SELINUX_CONTEXT': 'unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023',

 '_GID': 1000,

 'CODE_LINE': 1,

 '_HOSTNAME': '...',

 '_SYSTEMD_SESSION': 52,

 '_SYSTEMD_OWNER_UID': 1000,

 'MESSAGE': 'testing 1,2,3',

 '__MONOTONIC_TIMESTAMP':

    journal.Monotonic(timestamp=datetime.timedelta(2, 76200, 811585),

                      bootid=UUID('958b7e26-df4c-453a-a0f9-a8406cb508f2')),

 'SYSLOG_IDENTIFIER': 'python3',

 '_UID': 1000,

 '_EXE': '/usr/bin/python3',

 '_PID': 7733,

 '_COMM': '...',

 'CODE_FUNC': '<module>',

 'CODE_FILE': '<doctest journal.rst[4]>',

 '_SOURCE_REALTIME_TIMESTAMP':

     datetime.datetime(2015, 9, 5, 13, 17, 4, 944355),

 '__CURSOR': 's=...',

 '_BOOT_ID': UUID('958b7e26-df4c-453a-a0f9-a8406cb508f2'),

 '_CMDLINE': '/usr/bin/python3 ...',

 '_MACHINE_ID': UUID('263bb31e-3e13-4062-9bdb-f1f4518999d2'),

 '_SYSTEMD_SLICE': 'user-1000.slice',

 '_AUDIT_SESSION': 52,

 '__REALTIME_TIMESTAMP': datetime.datetime(2015, 9, 5, 13, 17, 4, 945110),

 '_SYSTEMD_UNIT': 'session-52.scope',

 '_SYSTEMD_CGROUP': '/user.slice/user-1000.slice/session-52.scope',

 '_TRANSPORT': 'journal'}

Avec cette API, il est assez facile de faire une application de log simple et fiable

Conclusion

Journald est un système de gestion moderne. Il a été construit en pleine connaissance des limitations des syslog traditionnels UNIX et s'appuie sur cette expérience pour fournir un système qui résout les problèmes auxquels nous sommes régulièrement confrontés dans le déploiement de nos systèmes.

Journalctl demande un peu de temps pour retrouver ses marques sur les commandes que l'on utilise au quotidien dans l'administration, mais une fois que l'on a passé ce cap, c'est un outil dont on ne peut plus se passer au quotidien.